/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package transaction_manager_core;

import txml.TransactionXmlLogger;
import txml.TransactionXmlLoggerException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.UUID;
import javax.ejb.Stateless;
import javax.ejb.LocalBean;
import replica_manager_client.ReplicaManagerAccessor;

import org.w3c.dom.*;
import javax.xml.parsers.*;

/**
 *
 * @author iMarshall
 */
@Stateless
@LocalBean
public class TransactionManagerCore {

    HashMap<String, LinkedList<String>> transactionPeers;
    String selfEndpoint;

    TransactionXmlLogger logger;


    public TransactionManagerCore() {
        transactionPeers = new HashMap<String, LinkedList<String>>();

        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse("taskman_config.xml");
            Element root = doc.getDocumentElement();

            NodeList ipaddrs = root.getElementsByTagName("IpAddress");
            NodeList ports = root.getElementsByTagName("WsdlPort");

            selfEndpoint = ((Element) ipaddrs.item(0)).getTextContent()
                + ":"
                + ((Element) ports.item(0)).getTextContent();

        } catch (Exception e) {
            System.err.println("error in constructor replica manager");
        }
    }

    public String openTransaction()
    {
        System.err.println("DEBUG::openTransaction:()");

        String peerId = selfEndpoint;
        UUID uuid = UUID.randomUUID();

        // create transaction id and participant list
        String tID = peerId + "_" + uuid.toString();
        transactionPeers.put(tID, new LinkedList<String>());

        logger = new TransactionXmlLogger("translog_coordinator", tID);

        try {
            logger.setTransactionStatus(TransactionXmlLogger.TransactionStatus.TRANSACTION_ACTIVE);
        } catch (TransactionXmlLoggerException ex) {
            ex.printStackTrace();
        }

        return tID;
    }

    public boolean closeTransaction(String tID)
    {
        System.err.println("DEBUG::preparing 2 phase commit :)");

        if (logger == null)
            logger = new TransactionXmlLogger("translog_coordinator", tID);

        try {
            logger.addValue("Prepare", "", "true");
            
        } catch (TransactionXmlLoggerException ex) {
            ex.printStackTrace();
        }

        for (String partecipant : transactionPeers.get(tID)) {
            System.err.println("DEBUG:: sending cancommit");
            ReplicaManagerAccessor rma =
                new ReplicaManagerAccessor("http://" + partecipant + "/ReplicaManager-war/ReplicaManagerWSService");

            try {
                if (rma.canCommit(tID) == false)
                    throw new VerifyError("transaction " + tID + " failed... ABORTING.");
                

            } catch (Exception ex) {
                abortTransaction(tID);
                return false;
            }
        }

        try {
            logger.addValue("GlobalCommit", "", "true");
            logger.setTransactionStatus(TransactionXmlLogger.TransactionStatus.TRANSACTION_2PC);

        } catch (TransactionXmlLoggerException e) {
            e.printStackTrace();
        }

        for (String partecipant : transactionPeers.get(tID)) {
            ReplicaManagerAccessor rma =
                new ReplicaManagerAccessor("http://" + partecipant + "/ReplicaManager-war/ReplicaManagerWSService");

            try {
                while (rma.doCommit(tID) == false);

            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        try {
            logger.addValue("Complete", "", "true");
            logger.setTransactionStatus(TransactionXmlLogger.TransactionStatus.TRANSACTION_COMMITTED);
        } catch (TransactionXmlLoggerException e) {
            e.printStackTrace();
            return false;
        }
        
        return true;
    }

    public boolean abortTransaction(String tID)
    {

        System.err.println("DEBUG::abortTransaction()");

        for (String partecipant : transactionPeers.get(tID)) {
            ReplicaManagerAccessor rma =
                new ReplicaManagerAccessor("http://" + partecipant + "/ReplicaManager-war/ReplicaManagerWSService");

            try {
                logger.addValue("GlobalAbort", "", "true");
                logger.setTransactionStatus(TransactionXmlLogger.TransactionStatus.TRANSACTION_ABORTED);

                rma.rollBack(tID);
                
            } catch (TransactionXmlLoggerException e) {
                e.printStackTrace();
                return false;
                        
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        
        try {
            logger.addValue("Complete", "", "true");
        } catch (TransactionXmlLoggerException e) {
            e.printStackTrace();
            return false;
        }

        return true;
    }

    public boolean join(String tID, String pID)
    {
        System.err.println("DEBUG::join:(" + tID + ", " + pID + ")"); 
        
        return transactionPeers.get(tID).add(pID);
    }

    public void haveCommitted(String tID, String pID)
    {
        
    }
}
